Validata
Type safe data validation and sanitization.
See also
Getting started
npm i validata
Basic usage
import { asString, isObject, isString, maybeString } from 'validata';
interface Sample {
maybeString: string | undefined;
myString: string;
numericString: string;
}
const sample = isObject<Sample>({
maybeString: maybeString(),
myString: isString(),
numericString: asString(),
});
console.log(
JSON.stringify(
sample.process({
maybeString: 123,
myString: 123,
numericString: 123,
})
)
);
console.log(
JSON.stringify(
sample.process({
myString: '123',
numericString: 123,
})
)
);
API
Checks:
- isAny
- Array
- isArray
- maybeArray
- asArray
- maybeAsArray
- Boolean
- isBoolean
- maybeBoolean
- asBoolean
- maybeAsBoolean
- Date
- isDate
- maybeDate
- asDate
- maybeAsDate
- Enum
- isEnum
- maybeEnum
- asEnum
- maybeAsEnum
- Number
- isNumber
- maybeNumber
- asNumber
- maybeAsNumber
- Object
- isObject
- maybeObject
- asObject
- maybeAsObject
- Record
- isRecord
- maybeRecord
- asRecord
- maybeAsRecord
- String
- isString
- maybeString
- asString
- maybeAsString
- Tuple
- Url
- isUrl
- maybeUrl
- asUrl
- maybeAsUrl
- isNullable
- asNullable
Types
Work is done by a typed ValueProcessor
, as returned byisObject<T>()
or asNumber()
.
interface ValueProcessor<T> {
process(value: unknown): Result<T>;
}
The process()
method returns a Result<T>
.The Result
is either a list of issues
(meaning validation failures) or the accepted value (it may be coerced/altered from the original).
type Result<T> = ValueResult<T> | IssueResult;
interface ValueResult<T> {
value: T;
}
interface IssueResult {
issues: Issue[];
}
Naming conventions
is...
e.g. isNumber
- if the value is of the type it will be accepted
null
or undefined
cause an issue
- otherwise it will cause an issue
maybe...
e.g. maybeNumber
- if the value is of the type it will be accepted
null
or undefined
it will sanitized to undefined
- otherwise it will cause an issue
as...
e.g. asNumber
- if the value is of the type it will be accepted
null
or undefined
converted to default, if provided, or cause an issue
- if the value can be converted to the type, it will be converted and used
- if the value is cannot be converted the default will be used if provided
- otherwise it will cause an issue
maybeAs...
e.g. maybeAsNumber
- if the value is of the type it will be accepted
null
or undefined
converted to default, if provided, or sanitized to undefined
- if the value can be converted to the type it will be converted and used
- if the value is cannot be converted the default will be used if provided
- otherwise it will cause an issue
// * otherwise it will be sanitized to undefined
Checks
isArray
, maybeArray
, asArray
, maybeAsArray
Usage:
isArray(itemProcessor, options);
maybeArray(itemProcessor, options);
asArray(itemProcessor, options);
maybeAsArray(itemProcessor, options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined or undefined
is returned then built in conversions will be run
convertOptions
- options to pass to the converter
coerceMaxLength? number
- if there are more items than this, some will be removed
maxLength?: number
- if there are more items than this, it's an error max-length
minLength?: number
- if there are less items than this, it's an error min-length
validator?: (value: T, options?: any) => boolean
- custom validation function; if false is returned it's an error
validatorOptions?: any
- options to pass to the validator
Example:
isArray<number>(isNumber({ max: 20, min: 10 }), { coerceMaxLength: 7 });
isBoolean
, maybeBoolean
, asBoolean
, maybeAsBoolean
Usage:
isBoolean(options);
maybeBoolean(options);
asBoolean(options);
maybeAsBoolean(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined or undefined
is returned then built in conversions will be run
convertOptions
- options to pass to the converter
validator?: (value: T, options?: any) => boolean
- custom validation function; if false is returned it's an error
validatorOptions?: any
- options to pass to the validator
isDate
, maybeDate
, asDate
, maybeAsDate
Usage:
isDate(options);
maybeDate(options);
asDate(options);
maybeAsDate(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined or undefined
is returned then built in conversions will be run
convertOptions
- options to pass to the converter
format
- custom date format used in conversion from string
to Date
see Luxon formatting
maxFuture?: Duration
- if the value is after this duration into the future, it's an error max-future
maxPast?: Duration
- if the value is before this duration into the past, it's an error max-past
validator?: (value: T, options?: any) => boolean
- custom validation function; if false is returned it's an error
validatorOptions?: any
- options to pass to the validator
isEnum
, maybeEnum
, asEnum
, maybeAsEnum
Usage:
isEnum(Enum);
maybeNumber(Enum);
asNumber(Enum);
maybeAsNumber(Enum);
Example:
enum EnumOne {
A = 'A',
B = 'B',
C = 'C',
}
isEnum(EnumOne);
enum EnumTwo {
A,
B,
C,
}
isEnum(EnumTwo);
asEnum(EnumTwo);
asEnum(EnumTwo).process('A'));
asEnum(EnumTwo).process(0));
asEnum(EnumTwo).process(EnumOne.A));
isNumber
, maybeNumber
, asNumber
, maybeAsNumber
Usage:
isNumber(options);
maybeNumber(options);
asNumber(options);
maybeAsNumber(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined or undefined
is returned then built in conversions will be run
convertOptions
- options to pass to the converter
coerceMin?: number
- if the value is less than this, it will be set to this value
coerceMax?: number
- if the value is more than this, it will be set to this value
max?: number
- if the value is than this, it's an error max
min?: number
- if the value is than this, it's an error min
validator?: (value: T, options?: any) => boolean
- custom validation function; if false is returned it's an error
validatorOptions?: any
- options to pass to the validator
isObject
, maybeObject
, asObject
, maybeAsObject
Usage:
isObject(contract, options);
maybeObject(contract, options);
asObject(contract, options);
maybeAsObject(contract, options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined or undefined
is returned then built in conversions will be run
convertOptions
- options to pass to the converter
validator?: (value: T, options?: any) => boolean
- custom validation function; if false is returned it's an error
validatorOptions?: any
- options to pass to the validator
Example:
interface Sample {
myString: string;
maybeString: string | undefined;
numericString: string;
}
const check = isObject<Sample>({
maybeString: maybeString(),
myString: isString(),
numericString: asString(),
});
isRecord
, maybeRecord
, asRecord
, maybeAsRecord
Usage:
isRecord<V>(check, options);
maybeRecord<V>(check, options);
asRecord<V>(check, options);
maybeAsRecord<V>(check, options);
Options:
keyRegex?: RegExp
- regular expression to check each key name, or it's an error key-regex
maxKeys?: number
- if the number of keys in the object is more than this, it's an error max-keys
minKeys?: number
- if the number of keys in the object is more than this, it's an error max-keys
validator?: (value: Record<string, V>, options?: any) => boolean
- custom validation function; if false is returned it's an error
validatorOptions?: any
- options to pass to the validator
Example:
const check = isRecord(isString());
check.process({ foo: 'bar' });
isString
, maybeString
, asString
, maybeAsString
Usage:
isString(options);
maybeString(options);
asString(options);
maybeAsString(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined or undefined
is returned then built in conversions will be run
convertOptions
- options to pass to the converter
limitLength?: number
- if the length of the string is more than this, it will be truncated to this length
padStart?: StringPadding
- pad the start of the string up to given value
padEnd?: StringPadding
- pad the end of the string up to given value
trim?: 'start' | 'end' | 'both' | 'none'
- removes the leading and/or trailing white space and line terminator characters from the string
regex?: RegExp
- regular expression that must be matched, or it's an error regex
maxLength?: number
- if the length of the string is more than this, it's an error max-length
minLength?: number
- if the length of the string is less than this, it's an error min-length
format:? StringFormatCheck
- extension point for string format checking, if check fails it's an issue format
with info.expectedFormat
set
validator?: (value: T, options?: any) => boolean
- custom validation function; if false is returned it's an error
validatorOptions?: any
- options to pass to the validator
StringPadding:
length: number
- will pad up until this length
padWith: string
- the value to pad with
StringFormat:
Example:
const check = isString({
limitLength: 6,
padStart: { length: 6, padWith: '-' },
});
const check = isString({
format: StringFormat.ULID(),
});
const check = isString({
format: StringFormat.password({
minLength: 10,
numberChars: 2,
lowerCaseChars: 2,
upperCaseChars: 2,
specialChars: 0,
}),
});
import { pascalCase } from 'change-case';
const check = isString({
transform: pascalCase,
});
const check = isString({
maxLength: 10,
minLength: 8,
regex: /^[A-Z]+$/,
});
import validator from 'validator';
const check = isString({
validator: validator.isEmail,
validatorOptions: { allow_display_name: true },
});
isTuple
, maybeTuple
Usage:
isTuple(options);
maybeTuple(options);
Options:
validator?: (value: T, options?: any) => boolean
- custom validation function; if false is returned it's an error
validatorOptions?: any
- options to pass to the validator
Example:
type MyTuple = [number, string];
const check = isTuple([isNumber({ max: 9, min: 3 }), isString({ regex: /^\w+$/ })]);
isUrl
, maybeUrl
, asUrl
, maybeAsUrl
Working with Node's URL object
Usage:
isUrl(options);
maybeUrl(options);
asUrl(options);
maybeAsUrl(options);
Options:
converter?: (value: unknown, options?: any) => T | undefined
- custom converter function, if not defined or undefined
is returned then built in conversions will be run
convertOptions
- options to pass to the converter
setProtocol?: string
- will coerce the protocol to the given value, if present
protocol?: string
- given URL must have this protocol, or it's an error invalid-protocol
validator?: (value: URL, options?: any) => boolean
- custom validation function; if false is returned it's an error
validatorOptions?: any
- options to pass to the validator
Example:
const check = asUrl({
protocol: 'https',
});
isNullable
Any other check can be wrapped into isNullable
to accept null
.
Example:
const check = isNullable(isString({ min: 3 }));
asNullable
Any other check can be wrapped into asNullable
to accept null
.
Options:
default
- can be null
or return type or a function with return type of the wrapped check
Example:
const check = asNullable(isString({ min: 3 }));
const check = asNullable(isString({ min: 3 }), { default: null });
const check = asNullable(isString({ min: 3 }), { default: 'text' });
const check = asNullable(isString({ min: 3 }), { default: () => 'text' });
Types
Types can be extracted from a ValueProcessor
or a Contract
-like pure object.
const sampleContract = {
maybeString: maybeString(),
myString: isString(),
numericString: asString(),
};
const sample = isObject(sampleContract);
export type SampleContract = TypeOf<typeof sample>;
export type Sample = TypeOf<typeof sample>;